package controllers

import (
	"fmt"
	"gitee.com/ha666/golibs"
	"github.com/astaxie/beego"
	"github.com/astaxie/beego/logs"
	"github.com/garyburd/redigo/redis"
	"ha666web/initial"
	"ha666web/models"
	"strconv"
	"strings"
)

type BaseController struct {
	LimitingController
	UserId   int64
	UserNick string
	Email    string
}

func (this *BaseController) Prepare() {
	key := fmt.Sprintf("fc_get_%s_%d", this.Ctx.Input.IP(), golibs.Unix()/600)
	beyond, errmsg := this.Limiting("get", key, 1200)
	if beyond {
		ipblacklist := &models.Ipblacklist{
			IP:       this.Ctx.Input.IP(),
			Status:   1,
			ExpireIn: golibs.Unix() + 86400,
		}
		issuccess, err := models.InsertUpdateIpblacklist(*ipblacklist)
		if err != nil {
			logs.Error("【Prepare】IP:%s,写入黑名单出错:%s", ipblacklist.IP, err.Error())
		} else {
			if !issuccess {
				logs.Error("【Prepare】IP:%s,写入黑名单失败", ipblacklist.IP)
			} else {
				logs.Info("【Prepare】IP:%s,写入黑名单成功")
			}
		}
		this.CustomAbort(403, "10分钟内get请求超频,"+errmsg)
		return
	}
	user_login := this.GetSession("user_login")
	if user_login == nil {
		if strings.EqualFold(strings.ToLower(this.Ctx.Request.Method), "get") {
			this.Redirect("/login", 302)
		} else {
			this.CustomAbort(200, golibs.ToJson(map[string]interface{}{"code": 0, "message": "未登录"}))
		}
		return
	} else {
		tmp := strings.Split(user_login.(string), "||")
		this.UserId, _ = strconv.ParseInt(tmp[0], 10, 64)
		this.UserNick = tmp[1]
		this.Email = tmp[2]
		this.Data["userid"] = this.UserId
		this.Data["username"] = this.UserNick
		this.Data["email"] = this.Email
	}
}

type LimitingController struct {
	beego.Controller
}

func (this *LimitingController) Limiting(method, key string, limit int) (bool, string) {
	if method != "all" && method != strings.ToLower(this.Ctx.Request.Method) {
		return false, ""
	}
	rc := initial.RedisClient.Get()
	if rc.Err() != nil {
		return false, rc.Err().Error()
	}
	defer rc.Close()
	count, err := redis.Int(rc.Do("GET", key))
	if err != nil {
		if strings.Contains(err.Error(), "nil returned") {
			errmsg := init_fc_key(key)
			if len(errmsg) > 0 {
				logs.Error("【control_flow】生成缓存出错:%s", err.Error())
				return false, errmsg
			}
			count = 1
			return false, ""
		} else {
			logs.Error("【control_flow】查询缓存出错:%s", err.Error())
			return false, err.Error()
		}
	}
	if count >= limit {
		return true, ""
	}
	set_result, err := redis.Int(rc.Do("INCR", key))
	if err != nil {
		logs.Error("【control_flow】写入缓存出错:%s", err.Error())
		return false, err.Error()
	}
	if set_result < 1 {
		logs.Error("【control_flow】写入缓存失败")
		return false, "写入缓存失败"
	}
	if set_result > limit {
		redis.Int(rc.Do("DECR", key))
		logs.Error("【control_flow】超频了" + strconv.Itoa(set_result))
		return true, ""
	}
	return false, ""
}

func init_fc_key(k string) (errmsg string) {
	set_result, err := set_flow_count(k)
	if err != nil {
		return err.Error()
	}
	if set_result != "OK" {
		return set_result
	} else {
		return ""
	}
}

func set_flow_count(time_name string) (msgs string, err error) {
	rc := initial.RedisClient.Get()
	defer rc.Close()
	return redis.String(rc.Do("SET", time_name, "1", "EX", "86400"))
}
